"""抖音JSON导出模块 - 基于embyAdapter.ts的实际实现"""

import json
import logging
import os
import subprocess
from pathlib import Path
from typing import List, Dict, Any
from datetime import datetime
from embytools.emby_client import EmbyClient

logger = logging.getLogger(__name__)


async def generate_emby_video_url(emby_server: str, video_id: str, api_key: str) -> str:
    """
    生成Emby视频播放URL - 基于embyAdapter.ts的实际实现
    格式：{emby_server}/emby/Videos/{video_id}/stream.mp4?api_key={api_key}
    """
    # 确保emby_server不以/结尾
    if emby_server.endswith('/'):
        emby_server = emby_server[:-1]
    return f"{emby_server}/emby/Videos/{video_id}/stream.mp4?api_key={api_key}"


async def generate_emby_cover_url(emby_server: str, video_id: str, api_key: str) -> str:
    """
    生成Emby封面图片URL - 基于embyAdapter.ts的实际实现
    格式：{emby_server}/Items/{video_id}/Images/Primary?api_key={api_key}
    """
    # 确保emby_server不以/结尾
    if emby_server.endswith('/'):
        emby_server = emby_server[:-1]
    return f"{emby_server}/Items/{video_id}/Images/Primary?api_key={api_key}"


async def convert_emby_to_douyin_format(
    emby_item: dict, 
    emby_server: str, 
    api_key: str,
    library_id: str,
    library_name: str
) -> dict:
    """
    基于embyAdapter.ts的实际实现进行转换
    """
    
    # 获取基础信息
    video_id = emby_item.get("Id", "")
    
    # 生成正确的URL（基于embyAdapter.ts）
    play_url = await generate_emby_video_url(emby_server, video_id, api_key)
    cover_url = await generate_emby_cover_url(emby_server, video_id, api_key)
    
    # 时长转换（embyAdapter.ts中的精确算法）
    runtime_ticks = emby_item.get("RunTimeTicks", 0)
    # 确保runtime_ticks不是None再进行除法运算
    duration_seconds = int(runtime_ticks / 10000000) if runtime_ticks is not None else 0  # 1 tick = 100纳秒
    
    # 构建抖音格式（基于embyAdapter.ts的实际结构）
    douyin_video = {
        "aweme_id": video_id,
        "desc": emby_item.get("Name", ""),
        "create_time": int(datetime.now().timestamp()),
        "video": {
            "play_addr": {
                "url_list": [play_url]
            },
            "cover": {
                "url_list": [cover_url]
            },
            "duration": duration_seconds
        },
        "author": {
            "nickname": library_name or "Emby媒体库"
        }
    }
    
    # 可选字段处理
    width = emby_item.get("Width")
    height = emby_item.get("Height")
    if width is not None and height is not None:
        douyin_video["video"]["width"] = width
        douyin_video["video"]["height"] = height
    
    # 添加必需的统计信息字段（基于embyAdapter.ts的要求）
    community_rating = emby_item.get("CommunityRating", 0)
    if community_rating is not None and community_rating > 0:
        digg_count = int(community_rating * 1000)
        comment_count = int(community_rating * 100)
        share_count = int(community_rating * 50)
        collect_count = int(community_rating * 20)
        play_count = int(community_rating * 2000)
    else:
        digg_count = comment_count = share_count = collect_count = play_count = 0
    
    douyin_video["statistics"] = {
        "digg_count": digg_count,
        "comment_count": comment_count,
        "collect_count": collect_count,
        "share_count": share_count,
        "play_count": play_count
    }
    
    # 添加必需的布尔字段（基于embyAdapter.ts的要求）
    douyin_video["isLoved"] = False
    douyin_video["isCollect"] = False
    douyin_video["isAttention"] = False
    
    # 添加Emby特有数据
    douyin_video["embyData"] = {
        "id": video_id,
        "libraryId": library_id,
        "type": "video",
        "year": emby_item.get("ProductionYear", datetime.now().year)
    }
    
    return douyin_video


def find_seven_zip() -> str:
    """
    查找7z可执行文件的路径（跨平台兼容）
    
    Returns:
        7z可执行文件的完整路径，如果未找到则返回None
    """
    import platform
    
    # 根据操作系统使用不同的查找方式
    if platform.system() == 'Windows':
        # Windows系统：使用where命令
        try:
            result = subprocess.run(['where', '7z'], capture_output=True, text=True)
            if result.returncode == 0 and result.stdout.strip():
                return result.stdout.strip().split('\n')[0]  # 返回第一个匹配的路径
        except:
            pass
        
        # 检查常见的Windows 7-Zip安装路径
        common_paths = [
            r'C:\\Program Files\\7-Zip\\7z.exe',
            r'C:\\Program Files (x86)\\7-Zip\\7z.exe',
            r'D:\\Program Files\\7-Zip\\7z.exe',
            r'D:\\Program Files (x86)\\7-Zip\\7z.exe'
        ]
    else:
        # Linux/Unix系统：使用which命令
        try:
            result = subprocess.run(['which', '7z'], capture_output=True, text=True)
            if result.returncode == 0 and result.stdout.strip():
                return result.stdout.strip()
        except:
            pass
        
        # 检查常见的Linux安装路径
        common_paths = [
            '/usr/bin/7z',
            '/usr/local/bin/7z',
            '/opt/bin/7z'
        ]
    
    # 检查常见路径
    for path in common_paths:
        if os.path.exists(path):
            return path
    
    return None

def compress_json_to_md(json_file_path: str) -> str:
    """
    将JSON文件压缩为7z格式并将扩展名改为.md
    
    Args:
        json_file_path: JSON文件路径
    
    Returns:
        压缩后的.md文件路径，如果压缩失败则返回None
    """
    # 构建目标文件名
    base_name = os.path.splitext(json_file_path)[0]
    sevenz_file_path = base_name + '.7z'
    md_file_path = base_name + '.md'
    
    try:
        # 查找7z可执行文件
        seven_zip_path = find_seven_zip()
        
        if not seven_zip_path:
            logger.warning("未找到7z可执行文件。请确保7-Zip已安装且在系统PATH中，或安装在常见位置。")
            logger.warning("压缩功能将被跳过，但JSON文件仍会正常生成。")
            return None
        
        logger.info(f"找到7z可执行文件: {seven_zip_path}")
        # 规范化路径显示，确保在所有平台上使用一致的分隔符
        norm_json_path = json_file_path.replace('\\', '/')
        norm_7z_path = sevenz_file_path.replace('\\', '/')
        logger.info(f"开始压缩文件: {norm_json_path} -> {norm_7z_path}")
        
        # 使用找到的7z路径直接执行压缩命令，避免PowerShell引号解析问题
        command = [
            seven_zip_path,
            'a',
            '-t7z',
            sevenz_file_path,
            json_file_path,
            '-mx=9'
        ]
        
        result = subprocess.run(command, capture_output=True, text=True)
        
        if result.returncode != 0:
            logger.error(f"压缩失败: {result.stderr}")
            logger.info("压缩失败，但JSON文件仍会正常生成。")
            # 压缩失败时不抛出异常，而是返回None
            return None
        
        # 重命名为.md文件
        if os.path.exists(sevenz_file_path):
            os.rename(sevenz_file_path, md_file_path)
            logger.info(f"文件已重命名为: {md_file_path}")
            return md_file_path
        else:
            logger.error(f"压缩文件不存在: {sevenz_file_path}")
            # 压缩文件不存在时不抛出异常，而是返回None
            return None
    except Exception as e:
        logger.error(f"压缩过程中发生错误: {str(e)}")
        logger.info("压缩失败，但JSON文件仍会正常生成。")
        # 如果压缩失败，尝试清理可能创建的7z文件
        if os.path.exists(sevenz_file_path):
            try:
                os.remove(sevenz_file_path)
            except:
                pass
        # 捕获所有异常并返回None，不影响主程序运行
        return None

def create_emby_client_from_credentials(emby_server: str, api_key: str) -> EmbyClient:
    """
    从凭据创建EmbyClient实例
    """
    # 解析服务器地址，提取host、port和https信息
    config = {
        'token': api_key,
        'host': 'localhost',
        'port': 8096,
        'https': False,
        'name': 'main',
        'user_id': ''
    }
    
    # 处理emby_server地址
    if emby_server.startswith('https://'):
        config['https'] = True
        emby_server = emby_server[8:]
    elif emby_server.startswith('http://'):
        emby_server = emby_server[7:]
    
    # 提取host和port
    if ':' in emby_server:
        parts = emby_server.split(':')
        config['host'] = parts[0]
        port_part = parts[1].split('/')[0]  # 处理可能的路径部分
        try:
            config['port'] = int(port_part)
        except ValueError:
            logger.warning(f"无效的端口号: {port_part}，使用默认端口8096")
    else:
        config['host'] = emby_server.split('/')[0]
    
    return EmbyClient(config)


async def get_videos_by_library(emby_client: EmbyClient, library_id: str, params: Dict[str, str]) -> Dict[str, Any]:
    """
    获取媒体库视频列表
    适配设计文档中的需求
    """
    try:
        user_id = await emby_client.get_user_id()
        
        # 使用items_api获取视频
        response = emby_client.items_api.get_items(
            user_id=user_id,
            parent_id=library_id,
            **params
        )
        
        # 转换为设计文档期望的格式
        videos = []
        for item in response.items:
            # 将对象转换为字典
            item_dict = {
                'Id': item.id,
                'Name': item.name,
                'RunTimeTicks': getattr(item, 'run_time_ticks', 0),
                'Width': getattr(item, 'width', None),
                'Height': getattr(item, 'height', None),
                'ProductionYear': getattr(item, 'production_year', None),
                'CommunityRating': getattr(item, 'community_rating', 0)
            }
            videos.append(item_dict)
        
        return {
            'success': True,
            'videos': videos,
            'message': f"成功获取 {len(videos)} 个视频"
        }
    except Exception as e:
        logger.error(f"获取视频失败: {e}")
        return {
            'success': False,
            'videos': [],
            'message': str(e)
        }


async def export_emby_library_to_douyin_json(
    library_id: str,
    library_name: str,
    emby_server: str,
    api_key: str,
    max_videos: int = None,  # 默认导出所有视频
    only_portrait_videos: bool = False,  # 仅纵向视频
    compress_to_md: bool = True,  # 是否自动压缩为.md文件
    output_filename: str = None  # 自定义输出文件名（不含扩展名）
) -> dict:
    """
    导出Emby媒体库到抖音JSON格式
    
    Args:
        library_id: 媒体库ID
        library_name: 媒体库名称
        emby_server: Emby服务器地址
        api_key: Emby API密钥
        max_videos: 最大导出视频数量，None表示导出所有视频
        only_portrait_videos: 仅纵向视频（宽<高）
        compress_to_md: 是否自动压缩为.md文件
        output_filename: 自定义输出文件名（不含扩展名），默认使用source_{library_id}_videos
    
    Returns:
        dict: 包含导出结果的字典，包括JSON文件路径、压缩文件路径等信息
    """
    # 固定使用当前工作目录下的data/douyin目录
    output_dir = os.path.join('data', 'douyin')
    
    # 确保输出目录存在
    os.makedirs(output_dir, exist_ok=True)
    
    # 创建Emby客户端
    emby_client = create_emby_client_from_credentials(emby_server, api_key)
    
    # 测试连接
    if not await emby_client.test_connection():
        raise Exception("Emby服务器连接失败")
    
    # 获取媒体库视频
    params = {
        "include_item_types": "Movie,Episode,Video",
        "recursive": "true",
        "fields": "MediaSources,MediaStreams,Width,Height,DateCreated,ProductionYear,RunTimeTicks,ImageTags,Overview",
        "sort_by": "DateCreated",
        "sort_order": "Descending"
    }
    
    # 仅当指定了max_videos时才添加limit参数
    if max_videos is not None:
        params["limit"] = str(max_videos)
    
    videos_result = await get_videos_by_library(emby_client, library_id, params)
    
    if not videos_result['success']:
        raise Exception(f"获取视频失败: {videos_result['message']}")
    
    # 构建完整的emby_server URL用于生成播放地址
    scheme = 'https' if emby_client.config.get('https', False) else 'http'
    full_emby_server = f"{scheme}://{emby_client.config['host']}:{emby_client.config['port']}"
    
    # 批量转换
    douyin_videos = []
    for video in videos_result['videos']:
        try:
            # 如果启用了纵向视频过滤，则检查宽高比
            if only_portrait_videos:
                width = video.get('Width')
                height = video.get('Height')
                # 只有当宽和高都存在且宽小于高时，才处理该视频
                if not (width is not None and height is not None and width < height):
                    logger.debug(f"跳过非纵向视频: {video.get('Name', video.get('Id', 'unknown'))} (宽: {width}, 高: {height})")
                    continue
            
            converted = await convert_emby_to_douyin_format(
                video, full_emby_server, api_key, library_id, library_name
            )
            douyin_videos.append(converted)
        except Exception as e:
            logger.error(f"转换视频 {video.get('Name', video.get('Id', 'unknown'))} 失败: {e}")
    
    # 生成输出文件名
    if output_filename is None:
        filename = f"source_{library_id}_videos"
    else:
        filename = output_filename
    output_filename = f"{filename}.json"
    output_filepath = os.path.join(output_dir, output_filename)
    
    # 保存JSON文件
    try:
        with open(output_filepath, 'w', encoding='utf-8') as f:
            json.dump(douyin_videos, f, ensure_ascii=False, indent=2)
        # 规范化路径显示，确保在所有平台上使用一致的分隔符
        normalized_path = output_filepath.replace('\\', '/')
        logger.info(f"JSON文件已保存到: {normalized_path}")
        
        # 压缩为.md文件（如果启用）
        compressed_file_path = None
        if compress_to_md:
            try:
                compressed_file_path = compress_json_to_md(output_filepath)
                if compressed_file_path:
                    # 规范化路径显示，确保在所有平台上使用一致的分隔符
                    norm_compressed_path = compressed_file_path.replace('\\', '/')
                    logger.info(f"压缩文件已生成: {norm_compressed_path}")
            except Exception as e:
                logger.error(f"压缩文件时出错: {str(e)}")
        
        # 返回导出结果信息
        return {
            'success': True,
            'video_count': len(douyin_videos),
            'json_file_path': output_filepath,
            'compressed_file_path': compressed_file_path,
            'message': f"成功导出 {len(douyin_videos)} 个视频"
        }
    except Exception as e:
        logger.error(f"保存JSON文件时出错: {str(e)}")
        raise Exception(f"保存JSON文件失败: {str(e)}")